#ifndef __LARGE_INTEGER_DATA_H__
#define __LARGE_INTEGER_DATA_H__

//for debug use.
#include <fstream>

namespace LARGE_INT {
	
	//************************************
	// 
	//************************************
	template<typename T, int N>
	class /*__declspec(align(16))*/ LargeInt {
		template<typename U, int M>
		friend class LIntOpAdpter;

		//for debug use.
		template<typename U, int M>
		friend std::ostream& operator<<(std::ostream &pStream, const LargeInt<U,M>& pData);

	public:
		typedef T ELEM_TYP;
		static const int SIZE = N;
		typedef LIntOpAdpter<T, N> ADP_TYP;
		typedef LIntOpAdpter<const T, N> const_ADP_TYP;

		LargeInt() {
			clearMem();
		}

		LargeInt(const T *ppStart){
			memcpy(m_data, ppStart, N * sizeof(T));
		}

	private:
		void clearMem(){
			memset(m_data,0,sizeof(m_data));
		}

	//private:
	public:
		T m_data[N];
	};

	//Not const correct yet!
	template<typename T, int N>
	class LIntOpAdpter {
		template<typename U, int P>
		friend class LIntOpAdpter;
	public:
		typedef T ELEM_TYP;
		static const int SIZE = N;
		//************************************
		// Init from a LargeInt object
		//************************************
		template<typename U, int P>
		LIntOpAdpter(LargeInt<U,P> &pValRef, const int pStartP = 0)
			:m_data_ref(static_cast<T*>(pValRef.m_data + pStartP)){}

		template<typename U, int M>
		LIntOpAdpter(LIntOpAdpter<U,M>& pValAdp, const int pStartP = 0)
			:m_data_ref(static_cast<T*>(pValAdp.m_data_ref + pStartP)){}

		//************************************
		// Const type caster.
		// Seems doesn't work??
		//************************************
		operator LIntOpAdpter<const T,N>()
		{
			return LIntOpAdpter<const T,N>(const T*(m_data_ref));
		}

		//************************************
		// Access methods.
		//************************************
		T& operator[](const int idx) {
			return *(m_data_ref + idx);
		}

		const T& operator[](const int idx) const { 
			return *(m_data_ref + idx);
		}

		//************************************
		// Copy from another place.
		//************************************
		template<typename U, int M>
		void copyMem(const LIntOpAdpter<U,M> &pStart, const int pOffset=0)
		{
			const int S = M>N?N:M;
			memcpy(m_data_ref,pStart.m_data_ref+pOffset,sizeof(T)*S);
		}

		T* get()const
		{
			return m_data_ref;
		}
	
	private:
		T		*m_data_ref;

		//************************************
		// For const type caster.
		//************************************
		template<typename Y>
		LIntOpAdpter(Y* ppDataRef):m_data_ref(ppDataRef){}
	};

	//************************************
	// For debug use.
	//************************************
	template<typename T, int N>
	std::ostream& operator<<(std::ostream &pStream, const LargeInt<T,N>& pData) {
		for ( int i=N-1;i>=0;i-- )
		{
			pStream.width(8);
			pStream<<std::hex<<std::right<<pData.m_data[i];
		}
		return pStream;
	}

}

#endif